//
//  CommandLineAppLauncher
//  SwiftTools
//
//  Created by Samuel Richard Magny on 15-10-03.
//  Copyright © 2015 Samuel Richard Magny. All rights reserved.
//

import Cocoa

public class CommandLineAppLauncher: AppLauncher {

    public typealias PipeOutputBlock = (String)->(Bool)
    
    private var outputPipe: NSPipe = NSPipe()
    private var inputPipe: NSPipe = NSPipe()
    private var errorPipe: NSPipe = NSPipe()
    
    private let encodingType:UInt = NSASCIIStringEncoding
    
    private var pipeObservers:Array<NSObjectProtocol> = []
    
    public var workingDirectory:String {
        get{
            return self.task.currentDirectoryPath
        }
        set(value){
            self.task.currentDirectoryPath = value
        }
    }
    
    public init(applicationPath:String, workingDirectory:String = "", outputBlock:PipeOutputBlock? = nil, errorBlock:PipeOutputBlock? = nil) {
        super.init()
        
        self.launchPath = applicationPath
        
        if !workingDirectory.isEmpty {
            self.workingDirectory = workingDirectory
        }
        
        self.task.standardInput = inputPipe
        self.task.standardOutput = outputPipe
        self.task.standardError = errorPipe
        
        if let outputFunctionBlock = outputBlock
        {
            initOutputPipe(outputPipe, receivedFunction:outputFunctionBlock)
        }
        
        if let errorFunctionBlock = errorBlock
        {
            initOutputPipe(errorPipe, receivedFunction:errorFunctionBlock)
        }
        
        
    }
    
    deinit
    {
        
        for pipeObserver in pipeObservers
        {
            NSNotificationCenter.defaultCenter().removeObserver(pipeObserver)
        }
    }
    
    public func write(input:String)
    {
        var inputStr = input
        if (inputStr.substringFromIndex(inputStr.endIndex.advancedBy(0)) != "\n")
        {
            inputStr.appendContentsOf("\n")
        }
        let inputData:NSData = inputStr.dataUsingEncoding(self.encodingType)!
        self.inputPipe.fileHandleForWriting.writeData(inputData)
    }
    
    private func initOutputPipe(pipe:NSPipe, receivedFunction:PipeOutputBlock)
    {
        let pipeObserver = NSNotificationCenter.defaultCenter().addObserverForName(NSFileHandleDataAvailableNotification, object: pipe.fileHandleForReading, queue: nil) { (notification) -> Void in
            
            let outputData: NSData = pipe.fileHandleForReading.availableData
            let dataString: NSString = NSString(data: outputData, encoding: self.encodingType)!
            
            if dataString.length > 0
            {
                if receivedFunction(dataString as String) //receivedFunction is a function and must be called only if "dataString" is not empty
                {
                    pipe.fileHandleForReading.waitForDataInBackgroundAndNotifyForModes([NSDefaultRunLoopMode])
                }
            }
        }
        
        pipe.fileHandleForReading.waitForDataInBackgroundAndNotifyForModes([NSDefaultRunLoopMode])
        
        pipeObservers.append(pipeObserver)
    }
    
}
